package com.zige.zige.view.panoplayer;

import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.Surface;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by admin on 16/1/5.
 */
public class VideoPlayer extends AbstractVideoPlayer implements
        MediaPlayer.OnPreparedListener,
        MediaPlayer.OnBufferingUpdateListener,
        MediaPlayer.OnSeekCompleteListener,
        MediaPlayer.OnErrorListener,
        MediaPlayer.OnCompletionListener,
        MediaPlayer.OnInfoListener {

    private final int IDLE = 0;
    private final int PREPARED = 1;
    private final int PLAYING = 2;
    private final int PAUSED = 3;
    private final int BUFFERING = 4;
    private int state = IDLE;
    private MediaPlayer player = new MediaPlayer();
    private float preloaded = 0.0f;
    private boolean seeking = false;
    private boolean seeking_once = false;
    private Timer progressTimer = new Timer();
    private Context context;
    private TimerTask progressTimerTask = new TimerTask() {
        @Override
        public void run() {
            if (null != videoStateListener) {
                float percentage = (0.0f + player.getCurrentPosition()) / player.getDuration();
                videoStateListener.onProgress(percentage, preloaded);
//                Log.w("progress", percentage + "");
            }
        }
    };

    public VideoPlayer(Context context) {
        this.context = context;
    }

    @Override
    public void prepare(String url) {
        try {
            player.setOnErrorListener(this);
            player.setOnPreparedListener(this);
            player.setOnBufferingUpdateListener(this);
            player.setOnInfoListener(this);
            player.setOnCompletionListener(this);
            player.setOnSeekCompleteListener(this);
            player.setLooping(autoLoop);
            player.setDataSource(context, Uri.parse(url), null);
            player.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void play() {
        switch (state) {
            case PREPARED:
                try {

                    player.start();
                    state = PLAYING;
                    if (null != videoStateListener) {
                        videoStateListener.onStarted();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            case PAUSED:
            case BUFFERING:
                try {
                    player.start();
                    state = PLAYING;
                    if (null != videoStateListener) videoStateListener.onResumed();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            default:
                break;
        }
    }

    @Override
    public void pause() {
        if (state == PLAYING) {
            player.pause();
            state = PAUSED;
            if (null != videoStateListener) videoStateListener.onPaused(false);
        }
    }

    @Override
    public void beforeSeek() {
        seeking = true;
        progressTimerTask.cancel();
    }

    @Override
    public void seekToPercentage(double percentage) {
//        if (seeking_once) return;
        seeking_once = true;
        player.seekTo((int) (percentage * player.getDuration()));
    }

    @Override
    public void afterSeek() {
        seeking = false;
        if (!seeking_once) progressTimerTask.run();
    }

    @Override
    public boolean isPlaying() {
        return player.isPlaying();
    }

    @Override
    public double getDuration() {
        return player.getDuration();
    }

    @Override
    public int getCurPosition() {
        return player.getCurrentPosition();
    }

    @Override
    public void setAutoLoop(boolean autoLoop) {
        super.setAutoLoop(autoLoop);
        player.setLooping(autoLoop);
    }

    @Override
    public void setProgressNotificationPeriod(double progressNotificationPeriod) {
        super.setProgressNotificationPeriod(progressNotificationPeriod);
        progressTimerTask.cancel();
        progressTimer.scheduleAtFixedRate(progressTimerTask, 0, (long) (progressNotificationPeriod * 1000));
    }

    @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
        float tmp = percent / 100.0f;
        if (tmp < preloaded) {
            if (state == PLAYING && !player.isPlaying()) {
                player.start();
//                if (null != videoStateListener) videoStateListener.onResumed();
            }
            return;
        }
        preloaded = tmp;
        if (null != videoStateListener) {
            videoStateListener.onProgress((player.getCurrentPosition() + 0.0f) / player.getDuration(), preloaded);
        }
        double deltaInSec = (preloaded * player.getDuration() - player.getCurrentPosition()) / 1000.0;
        if (state == BUFFERING && deltaInSec > preloadTime && autoPlayWhenBuffered) {
            player.start();
            if (null != videoStateListener) videoStateListener.onResumed();
        }
//        else if (state == PREPARED && deltaInSec > preloadTime && autoPlayWhenBuffered) {
//            videoStateListener.onPrepared(true);
//        }
        else if (state == PLAYING && deltaInSec > preloadTime && autoPlayWhenBuffered) {
            if (!player.isPlaying()) {
                player.start();
                if (null != videoStateListener) videoStateListener.onResumed();
            }
        }
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        state = PREPARED;
        player.start();
        player.pause();
        player.seekTo(0);
        if (null != videoStateListener) {
            videoStateListener.onPrepared(true);
            progressTimer.scheduleAtFixedRate(progressTimerTask, 0, (long) (1000 * progressNotificationPeriod));
        }
    }

    @Override
    public void onSeekComplete(MediaPlayer mp) {
        if (state <= PREPARED) return;
        seeking_once = false;
        if (!seeking) progressTimerTask.run();
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        if (state == IDLE) {
            if (null != videoStateListener) videoStateListener.onPrepared(false);
        }
        return false;
    }

    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        switch (what) {
            case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
                player.pause();
                return true;
            case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                if (state == BUFFERING) {
                    double deltaInSec = (preloaded * player.getDuration() - player.getCurrentPosition()) / 1000.0;
                    if (autoPlayWhenBuffered && deltaInSec > preloadTime) {
                        player.start();
                        state = PLAYING;
                        if (null != videoStateListener) videoStateListener.onResumed();
                    }
                }
                return true;
            case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                if (state == PLAYING) {
                    state = BUFFERING;
                    if (null != videoStateListener) videoStateListener.onPaused(true);
                }
                return true;
            default:
                break;
        }
        return false;
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        if (null != videoStateListener) videoStateListener.onStopped();
    }

    @Override
    public void setSurface(Surface surface) {
        player.setSurface(surface);
    }

    @Override
    public void cleanUp() {
        try {
            progressTimerTask.cancel();
            progressTimer.cancel();
            progressTimer.purge();
            player.stop();
            player.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
